
package privatemessanger;
import java.util.ArrayList;
import java.io.IOException;
import java.net.ServerSocket;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * This class contains the information of a server.
 * An "open server" means that all clients see each other.
 * A "close server" means that each client sees only clients who are in the same type.
 * @author  Erez Fatal, Oren Slor, Elad Yanai, Sigal Agami, Chen Ben Shabat,
 *          Inbar Pardo, Islamm Heralla, Ziv Hadary, Oren Shalev, Ortal David.
 */
public class Server extends Thread
{
    private String _IP; // the IP of the server.
    private String _name; // the name of the server.
    private boolean _isOpen; // true means "open server". false means "close server".
    private boolean _isServer; // does this object is a real server.
    private ArrayList<Client> _clientArray; // array of clients.
    private ArrayList<ConnectToServer> _connectionArray; // array of connection.
    private ServerSocket _serverSocket;

    /**
     * This constructor is for client who plays as a server.
     * @param client The client who create this server.
     * @param name The server's name.
     * @param isOpen A flag for the server's kind.
     */
    public Server(Client client, String name, boolean isOpen)
    {
        _IP=client.getIP();
        _name=name;
        _isOpen=isOpen;
        _isServer=true;
        _clientArray=new ArrayList<Client>();
        _connectionArray=new ArrayList<ConnectToServer>();
        _clientArray.add(client);
        try {
            _serverSocket = new ServerSocket(MainFrame.PORT);
        } catch (IOException e) { System.err.println("something is wrong... :( "); System.exit(1); }
    }

    /**
     * This constructor is for client who not plays as a server.
     * @param IP The serever's IP.
     */
    public Server(String IP)
    {
        _IP=IP;
        _name="Server";
        _isOpen=true;
        _isServer=false;
        _clientArray=new ArrayList<Client>();
    }

    @Override
    /**
     * This method has to add new clients.
     */
    public void run()
    {
        while(true) // infinite loop "listening/waiting" for client.
        {
            System.out.println("waiting for a client...");
            try {
                ConnectToServer connect=new ConnectToServer(_serverSocket.accept()); // waiting untill the server accepts a client.
                _connectionArray.add(connect);
                connect.start();
            } catch (IOException ex) { Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex); }
        }
   }

    /**
     * Get the server's IP.
     * @return The server's IP.
     */
    public String getIP() { return _IP; }

    /**
     * Get the server's name.
     * @return The server's name.
     */
    public String getServerName() { return _name; }

    /**
     * Set the server's name.
     * @param name The server's new name.
     */
    public void setServerName(String name) { _name=name; }

    /**
     * This method check the server's kind.
     * @return If "open server"- true. if "close server"- false.
     */
    public boolean isOpen() { return _isOpen; }

    /**
     * this method checks if the server is a "real server".
     * @return If it is a "real server"- true, else false.
     */
    public boolean isServer() { return _isServer; }

    /**
     * Get the clients array.
     * @return The client array.
     */
    public ArrayList<Client> getClientArray() { return _clientArray; }

    /**
     * Get the connection array.
     * @return The connection array.
     */
    public ArrayList<ConnectToServer> getConnectionArray() { return _connectionArray; }

    /**
     * Get a client from the clients array.
     * @param ID The client's ID.
     * @param name The client's name.
     * @return if exist- The client, else null.
     */
    public Client getClient(int ID, String name)
    {
        for (int i=0; i<_clientArray.size(); i++)
        {
            if (_clientArray.get(i).getID()==ID && _clientArray.get(i).getUserName().equals(name))
                return _clientArray.get(i);
        }
        return null; // the client is not exist.
    }

    /**
     * This method adds a new client to the clients array.
     * @param client An instance of a client.
     */
    public void addClient(Client client)
    {
        _clientArray.add(client);
        if (!_isServer)
            return;
    }

    /**
     * This method removes a client from the clients array.
     * @param client An instance of a client.
     */
    public void removeClient(Client client) { _clientArray.remove(client); }

    /**
     * This method removes a client from the clients array.
     * @param ID The client's ID.
     * @param name The client's name.
     */
    public void removeClient(int ID, String name)
    {
        Client client=getClient(ID,name);
        removeClient(client);
    }

    /**
     * This method has to notify all contacts that the server is closing.
     */
    public void closeServer()
    {
        if (!_isServer)
            return;
        for (int i=0; i<_connectionArray.size(); i++)
        {
            Client client=_connectionArray.get(i).getClient();
            _connectionArray.get(i).writeSocket("DELETE_SERVER");
            removeClient(client);
        }
        removeClient(MainFrame._user);
        MainFrame._serverName.updateList();
    }
}
